package com.hqyj.springCloudAccount.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hqyj.entity.account.User;
import com.hqyj.entity.account.UserRole;
import com.hqyj.entity.common.ResultEntity;
import com.hqyj.entity.common.SearchBean;
import com.hqyj.entity.test.City;
import com.hqyj.springCloudAccount.dao.UserDao;
import com.hqyj.springCloudAccount.dao.UserRoleDao;
import com.hqyj.springCloudAccount.entity.UserVo;
import com.hqyj.springCloudAccount.service.TestOpenFeignClient;
import com.hqyj.springCloudAccount.service.UserService;
import com.hqyj.springCloudAccount.util.MD5Util;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.vavr.control.Try;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;


@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private TestOpenFeignClient testOpenFeignClient;

    @Override
    public User getUserByUserNameAndPassword(String userName, String password) {
        return userDao.getUserByUserNameAndPassword(userName,MD5Util.getMD5(password));
    }

    @Override
    public ResultEntity<User> login(User user) {
        User user_db = userDao.getUserByUserNameAndPassword(user.getUserName(),MD5Util.getMD5(user.getPassword()));
        if(user_db == null){
            return new ResultEntity<>(ResultEntity.ResultStatus.FAILED.status,"用户名或密码错误！");
        }
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"登录成功！");
    }

    @Override
    public ResultEntity<User> addUser(User user) {
        //判断用户名是否重复
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.size() > 0) {
            return new ResultEntity<User>(ResultEntity.ResultStatus.FAILED.status, "用户名或邮箱重复！");
        }
        user.setCreateDate(LocalDateTime.now());
        user.setPassword(MD5Util.getMD5(user.getPassword()));
        userDao.addUser(user);
        if (user.getRoles() != null) {
            user.getRoles().stream()
                    .forEach(item -> {userRoleDao.addtUserRole(new UserRole(user.getId(), item.getId()));});
        }
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"添加成功！",user);
    }

    @Override
    public ResultEntity<User> updateUserByUser(User user) {
        //判断用户名是否重复
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        //if(users.size() > 0 && users.get(0).getId() != user.getId())
        if (users.stream().filter(item -> item.getId() != user.getId()).count() > 0) {
            return new ResultEntity<User>(ResultEntity.ResultStatus.FAILED.status, "用户名或邮箱重复！");
        }
        userDao.updateUserByUser(user);
        // 当前端设置新的角色信息时
        if (user.getRoles() != null && !user.getRoles().isEmpty()) {
            // 根据用户 id，删除已有的角色信息
            userRoleDao.deleteUserRoleByUserId(user.getId());
            // 插入新的角色信息
            user.getRoles().stream()
                    .forEach(item -> {userRoleDao.addtUserRole(new UserRole(user.getId(), item.getId()));});
        }
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"修改成功！",user);
    }

    @Override
    public ResultEntity<User> deleteUserById(int id) {
        userDao.deleteUserById(id);
        userRoleDao.deleteUserRoleByUserId(id);
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"删除成功！");
    }

    @Override
    public User selectUserById(int id) {
        return userDao.selectUserById(id);
    }

    @Override
    public PageInfo<User> selectAllUser(SearchBean searchBean) {
        searchBean.initSearchBean();
        PageHelper.startPage(searchBean.getCurrentPage(),searchBean.getPageSize());
        return new PageInfo<>(Optional.ofNullable(userDao.SelectAllUserInPage(searchBean)).orElse(Collections.emptyList()));
    }

    @Override
    public User selectUserByUserName(String userName) {
        return userDao.selectUserByUserName(userName);
    }

    @Override
    public UserVo getUserVoById(int id) {
        UserVo userVo_db = userDao.getUserVoById(id);
        //127.0.0.1/api/city/2257    http://127.0.0.1:8761/api/city/{cityId} 因为test微服务可能是一个集群所以用CLIENT-TEST唯一标识来代替端口号
        //通过注册中心的唯一标识调用其他微服务的接口
//        City city_db = restTemplate.getForObject("http://CLIENT-TEST/api/city/{cityId}",
//                City.class,1890);//这个方法只返回body数据
        //restTemplate.getForEntity();//这个方法返回的是状态码，header数据，body数据
        /*
         * - 重试策略
         * - 在生产者接口里书写 1/0 运行时异常，调用该接口可查看生产者控制台，调用了三次
         */
//		RetryConfig retryConfig = RetryConfig
//				.custom()
//				.maxAttempts(3)
//				.waitDuration(Duration.ofMillis(3000))
//				.build();
//		Retry retry = Retry.of("retryPloy", retryConfig);
//		Try<City> retrySupplier = Try.ofSupplier(Retry.decorateSupplier(
//					retry,
//					() -> restTemplate.getForObject("http://client-test/api/city/{countryId}", City.class, 1890)
//				));
//		userVo_db.setCity(retrySupplier.get());

        /*
         * - 熔断器策略配置
         * - 生产者抛出异常或停掉的情况，都会返回默认值
         * - 当一个节点出现问题时不影响其他节点的运行
         */
        CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofMillis(1000))
                .build();
        CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
        Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
                circuitBreaker,
//				() -> restTemplate.getForObject("http://client-test/api/city/{countryId}", City.class, 1890)
//        )).recover(Exception.class, new City());
                //这里调用的是已经通过name标识的第三方接口
                () -> testOpenFeignClient.getCityByCityId(1890))).recover(Exception.class, new City());
        userVo_db.setCity(circuitBreakerSupplier.get());

        return userVo_db;
    }

    @Override
    public List<User> getUserByUserNameOrEmail(String userName, String email) {
        return Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(userName, email))
                .orElse(Collections.emptyList());
    }
}
